home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Magazine / C_Tutorial / Part-13 / PatchLib / source / IRFuncs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-22  |  15.5 KB  |  674 lines

  1. /*
  2. **    patch.library
  3. **
  4. **    Copyright © 1993-1997 by Stefan Fuchs
  5. **        Freely distributable.
  6. */
  7.  
  8. #ifndef _PATCH_INCLUDES_H
  9. #include "patch_includes.h"
  10. #endif
  11.  
  12. /* Functions used by InstallPatchTags() and RemovePatchTags() */
  13.  
  14.  
  15. /****i* patch.library/RemoveSystemNodeWithTest ***************************************
  16. *
  17. *   NAME
  18. *        RemoveSystemNodeWithTest -- Remove all nodes required for patching a
  19. *                                    function, if possible
  20. *
  21. *   SYNOPSIS
  22. *        error = RemoveSystemNodeWithTest( master )
  23. *
  24. *        ULONG RemoveSystemNodeWithTest( struct MasterPatch *);
  25. *
  26. *   FUNCTION
  27. *        Remove all nodes required for patching a function, if no
  28. *        PS_USER_TYPE or PS_SYSTEM_TYPE exists for the same function.
  29. *
  30. *   INPUTS
  31. *        master = pointer to a MasterPatch structure
  32. *
  33. *   RESULT
  34. *        error = errorcode as defined in patch.h
  35. *
  36. *   NOTES
  37. *
  38. *   BUGS
  39. *
  40. *   SEE ALSO
  41. *        RemoveSystemNode(), AddSystemNode(), patch.h
  42. *
  43. ******************************************************************************
  44. *
  45. */
  46.  
  47. ULONG RemoveSystemNodeWithTest( struct MasterPatch *master)
  48. {
  49. ULONG result = 0L;
  50.     if( FindType( (struct List *)(&(master->MPS_PatchHeader)), PS_TYPE_USER) == NULL)
  51.     {
  52.         if( FindType( (struct List*)(&(master->MPS_PatchHeader)), PS_TYPE_SYSTEM) == NULL)
  53.         {
  54.             result = RemoveSystemNode( master);
  55.         }
  56.     }
  57.     return( result);
  58. }
  59.  
  60.  
  61. /****i* patch.library/RemoveSystemNode ***************************************
  62. *
  63. *   NAME
  64. *        RemoveSystemNode -- Remove all nodes required for patching a
  65. *                            function, if possible
  66. *
  67. *   SYNOPSIS
  68. *        error = RemoveSystemNode( master )
  69. *
  70. *        ULONG RemoveSystemNode( struct MasterPatch *);
  71. *
  72. *   FUNCTION
  73. *        Remove all nodes required for patching a function.
  74. *        ( PS_TYPE_MASTER, PS_TYPE_START,PS_TYPE_ORIG,PS_TYPE_END)
  75. *        Step 1: Remove patches from the jump-table via DisconnectStartType()
  76. *        Step 2: Test, if PS_TYPE_START is in use
  77. *        Step 3: Remove PS_TYPE_ORIG
  78. *        Step 4: Remove PS_TYPE_START
  79. *        Step 5: Remove PS_TYPE_END
  80. *        Step 6: CloseLibObject()
  81. *        Step 7: Remove PS_TYPE_MASTER
  82. *
  83. *   INPUTS
  84. *        master = pointer to a MasterPatch structure
  85. *
  86. *   RESULT
  87. *        error = errorcode as defined in patch.h
  88. *
  89. *   NOTES
  90. *
  91. *   BUGS
  92. *
  93. *   SEE ALSO
  94. *        AddSystemNode(), patch.h
  95. *
  96. ******************************************************************************
  97. *
  98. */
  99.  
  100. ULONG RemoveSystemNode( struct MasterPatch *master)
  101. {
  102. ULONG result;
  103.  
  104.     Forbid();
  105.     result = DisconnectStartType( master);
  106.     if( result == PATERR_Ok)
  107.     {
  108.         result = TestUsage( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START));
  109.         if( result == PATERR_Ok)
  110.         {
  111.             result = RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_ORIG));
  112.             if( result == PATERR_Ok)
  113.             {
  114.                 Permit();
  115. /* Nothing should cause an error after this point (handle is no longer valid) */
  116.                 RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START));
  117.                 RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_END));
  118.                 CloseLibObject( master->MPS_PatchedLibraryBase, master->MPS_PatchIORequest, master->MPS_Flags);
  119.                 RemStruct( (struct Patch *)master);
  120.                 return(PATERR_Ok);
  121.             }
  122.         }
  123.         ConnectStartType( master);
  124.     }
  125.     Permit();
  126.     return(result);
  127. }
  128.  
  129. /****i* patch.library/AddStruct ***************************************
  130. *
  131. *   NAME
  132. *        AddStruct -- Create a patch.library structure and add it to a list.
  133. *
  134. *   SYNOPSIS
  135. *        structure = AddStruct( header, name, type, pri )
  136. *
  137. *        APTR AddStruct( struct List *, STRPTR, UBYTE, BYTE);
  138. *
  139. *   FUNCTION
  140. *        Create a structure of the given type and and it to the given
  141. *        list. 
  142. *
  143. *   INPUTS
  144. *        header = pointer to a List structure
  145. *        name = pointer to a name for the structure (will be copied)
  146. *               (not supported for all types)
  147. *        type = type of structure to allocate ( PS_TYPE_xxx )
  148. *        pri = position, where to insert the node to the list
  149. *
  150. *   RESULT
  151. *        structure = newly created structure or NULL on failure
  152. *
  153. *   NOTES
  154. *
  155. *   BUGS
  156. *
  157. *   SEE ALSO
  158. *        RemStruct(), patch.h
  159. *
  160. ******************************************************************************
  161. *
  162. */
  163.  
  164. APTR AddStruct( struct List *header, STRPTR name, UBYTE type, BYTE pri)
  165. {
  166. struct Patch *patch;
  167. struct MasterPatch *master;
  168. ULONG array[2];
  169.  
  170.     switch(type)
  171.     {
  172.         case PS_TYPE_ORIG:
  173.         case PS_TYPE_USER:
  174.         case PS_TYPE_SYSTEM:
  175.             patch = (struct Patch *)ACreateMyListNodeNamedPri( header, sizeof( struct Patch), name, pri);
  176.             if(patch)
  177.             {
  178.                 patch->PS_Node.ln_Type = type;
  179.                 NewList( &(patch->PS_RemoveHookList));
  180.  
  181.                 if( PatchBase->PB_PatchSVActive)
  182.                 {
  183.                     PatchBase->PB_PatchSVRemoveable++;
  184.                     patch->PS_Flags |= PSF_PatchSV;
  185.                 }
  186.             }
  187.             return( patch);
  188.  
  189.  
  190.         case PS_TYPE_MASTER:
  191.             master = (struct MasterPatch *)ACreateMyListNodeNamed( header, sizeof( struct MasterPatch), name);
  192.             if( master)
  193.             {
  194.                 master->MPS_Node.ln_Type = type;
  195.                 NewList( (struct List*)&(master->MPS_PatchHeader));
  196.             }
  197.             return( master);
  198.  
  199.  
  200.         case PS_TYPE_START:
  201.             patch = (struct Patch *)ACreateMyListNodePri( header, sizeof( struct Patch), pri);
  202.             if(patch)
  203.             {
  204.                 patch->PS_Node.ln_Type = type;
  205.                 NewList( &(patch->PS_RemoveHookList));
  206.             }
  207.             return( patch);
  208.  
  209.  
  210.         case PS_TYPE_END:
  211.             patch = (struct Patch *)ACreateMyListNodePri( header, sizeof( struct Patch), pri);
  212.             if(patch)
  213.             {
  214.                 patch->PS_Node.ln_Type = type;
  215.                 NewList( &(patch->PS_RemoveHookList));
  216.  
  217.                 SetPCode( patch, TAG_DONE);
  218.                 GetPatchCodeTemplate( patch, array);
  219.                 patch->PS_PatchCode  = (struct PatchCode *)array[1];
  220.             }
  221.             return( patch);
  222.  
  223.  
  224.         default:
  225.             return( NULL);
  226.     }
  227. }
  228.  
  229. /****i* patch.library/CreatePatchCode ***************************************
  230. *
  231. *   NAME
  232. *        CreatePatchCode -- Create and initialize a patchcode.
  233. *
  234. *   SYNOPSIS
  235. *        patch = CreatePatchCode( patch )
  236. *
  237. *        struct Patch *CreatePatchCode( struct Patch *);
  238. *
  239. *   FUNCTION
  240. *        Create and initialize a patchcode for a given patch structure.
  241. *
  242. *   INPUTS
  243. *        patch = pointer to a Patch structure or NULL for no action
  244. *
  245. *   RESULT
  246. *        patch = pointer to a Patch structure or NULL on failure
  247. *
  248. *   NOTES
  249. *
  250. *   BUGS
  251. *
  252. *   SEE ALSO
  253. *        AddStruct(), patch.h
  254. *
  255. ******************************************************************************
  256. *
  257. */
  258.  
  259. struct Patch *CreatePatchCode( struct Patch *patch)
  260. {
  261. ULONG array[2];
  262.  
  263.     if(patch)
  264.     {
  265.         GetPatchCodeTemplate( patch, array);
  266.         patch->PS_PatchCode = BAllocmem( array[0], MEMF_CLEAR | MEMF_PUBLIC);
  267.         if( patch->PS_PatchCode)
  268.         {
  269.             CopyMem( (APTR) array[1], patch->PS_PatchCode, array[0]);
  270.             InitPatchCode( patch);
  271.         }
  272.         else
  273.         {
  274.             RemStruct( patch);
  275.             patch = NULL;
  276.         }
  277.         return( patch);
  278.     }
  279. }
  280. /****i* patch.library/SetPCode ***************************************
  281. *
  282. *   NAME
  283. *        SetPCode -- Set the PCode template in the given patch structure.
  284. *
  285. *   SYNOPSIS
  286. *        SetPCode( patch, taglist )
  287. *
  288. *        SetPCode( struct Patch *, struct TagItem *taglist);
  289. *
  290. *   FUNCTION
  291. *        Decide, which PCode template should be used for the given
  292. *        patch structure and taglist.
  293. *        The taglist is only used, for patches of PS_TYPE_USER or
  294. *        PS_TYPE_SYSTEM.
  295. *
  296. *   INPUTS
  297. *        patch = pointer to a Patch structure or NULL for no action
  298. *        taglist = pointer to a taglist as used with InstallPatchTags()
  299. *
  300. *   RESULT
  301. *
  302. *   NOTES
  303. *
  304. *   BUGS
  305. *
  306. *   SEE ALSO
  307. *        patch.h
  308. *
  309. ******************************************************************************
  310. *
  311. */
  312.  
  313. void SetPCode( struct Patch *patch, struct TagItem *taglist )
  314. {
  315. ULONG xresult;
  316. struct TagItem *origtag;
  317.     if(patch)
  318.     {
  319.         switch(patch->PS_Node.ln_Type)
  320.         {
  321.             case PS_TYPE_USER:
  322.                 xresult = GetTagData( PATT_UseXResult, 0L, taglist);
  323.                 origtag = FindTagItem(PATT_Original, taglist);
  324.                 if( patch->PS_Node.ln_Pri == 0)
  325.                 {
  326.                     if( xresult) patch->PS_PatchCodeType = PCODE_USER1;
  327.                     else         patch->PS_PatchCodeType = PCODE_USER0;
  328.                 }
  329.                 else
  330.                 {
  331.                     if( xresult)
  332.                     {
  333.                         if( origtag)
  334.                             patch->PS_PatchCodeType = PCODE_USER5;
  335.                         else     patch->PS_PatchCodeType = PCODE_USER3;
  336.                     }
  337.                     else
  338.                     {
  339.                         if( origtag)
  340.                             patch->PS_PatchCodeType = PCODE_USER4;
  341.                         else     patch->PS_PatchCodeType = PCODE_USER2;
  342.                     }
  343.                 }
  344.                 break;
  345.  
  346.             case PS_TYPE_SYSTEM:
  347.                 patch->PS_Flags |= PSF_OriginalType;    /* SystemType is handled like a UserType with PATT_ORIGINAL set */
  348.                                     /* This is only required for older versions of PatchSetFunc, */
  349.                                     /* which do not use PATT_Original */
  350.                 patch->PS_PatchCodeType = PCODE_SYSTEM;
  351.                 break;
  352.  
  353.             case PS_TYPE_ORIG:
  354.                 patch->PS_PatchCodeType = PCODE_ORIG;
  355.                 break;
  356.  
  357.             case PS_TYPE_START:
  358.                 patch->PS_PatchCodeType = PCODE_START;
  359.                 break;
  360.  
  361.             case PS_TYPE_END:
  362.                 patch->PS_PatchCodeType = PCODE_END;
  363.                 break;
  364.         }
  365.     }
  366. }
  367.  
  368.  
  369. /****i* patch.library/RemStruct ***************************************
  370. *
  371. *   NAME
  372. *        RemStruct -- Remove and deallocate a patch.library structure.
  373. *
  374. *   SYNOPSIS
  375. *        error = RemStruct( structure )
  376. *
  377. *        ULONG RemStruct( APTR);
  378. *
  379. *   FUNCTION
  380. *        Remove and deallocate a patch.library structure, if possible.
  381. *
  382. *   INPUTS
  383. *        structure = pointer to a patch.library structure
  384. *
  385. *   RESULT
  386. *        error = errorcode as defined in patch.h
  387. *
  388. *   NOTES
  389. *
  390. *   BUGS
  391. *
  392. *   SEE ALSO
  393. *        AddStruct(), patch.h
  394. *
  395. ******************************************************************************
  396. *
  397. */
  398. ULONG RemStruct( struct Patch *patch)
  399. {
  400. struct TagItem tlist[2];
  401. ULONG result;
  402. UBYTE *memptr;
  403.  
  404.     switch(patch->PS_Node.ln_Type)
  405.     {
  406.         case PS_TYPE_USER:
  407.         case PS_TYPE_DELUSER:
  408.         case PS_TYPE_SYSTEM:
  409.         case PS_TYPE_DELSYSTEM:
  410.         case PS_TYPE_ORIG:
  411.             if( patch->PS_PatchCode)
  412.             {
  413.                 result = TestUsage( patch);
  414.                 if( result) return(result);
  415.                 CallRemoveHooks( patch);
  416.                 tlist[0].ti_Tag = PATT_DeleteTaskList;
  417.                 tlist[0].ti_Data = 1L;
  418.                 tlist[1].ti_Tag = TAG_DONE;
  419.                 patch->PS_Flags |= PSF_InternalCall;
  420.                 SetPatchA( patch, tlist);
  421.                 if( patch->PS_ProjectNode.mln_Succ)
  422.                 {
  423.                     Remove( (struct Node *)&(patch->PS_ProjectNode));
  424.                 }
  425.                 if( patch->PS_UserPatchCodeSize)
  426.                 {
  427.                     memptr = patch->PS_Jsr;
  428.                     memptr += 2;
  429.                     AFreemem( (APTR)(*((ULONG *)memptr)) );
  430.                 }
  431.                 AFreemem( patch->PS_PatchCode);
  432.             }
  433.             if( patch->PS_Flags & PSF_PatchSV)
  434.                 PatchBase->PB_PatchSVRemoveable--;
  435.             break;
  436.  
  437.  
  438.         case PS_TYPE_MASTER:
  439.             if(((struct MasterPatch *)patch)->MPS_PatchHeader.mlh_Head->mln_Succ) /* Delete structure only, if Patchlist is empty */
  440.                 return(-1);
  441.             PreAllocatedStacksFree( (struct MasterPatch *)patch);
  442.             break;
  443.  
  444.  
  445.         case PS_TYPE_START:
  446.             if( patch->PS_PatchCode)
  447.             {
  448.                 result = TestUsage( patch);
  449.                 if( result) return( result);
  450.                 AFreemem( patch->PS_PatchCode);
  451.             }
  452.             break;
  453.  
  454.  
  455.         case PS_TYPE_END:
  456.             break;
  457.  
  458.  
  459.         default:
  460.             return(-1);
  461.     }
  462.     ADeleteMyListNode( (struct Node *)patch);
  463.     return(PATERR_Ok);
  464. }
  465.  
  466.  
  467. /****i* patch.library/CloseLibObject ***************************************
  468. *
  469. *   NAME
  470. *        CloseLibObject -- Close a library type object.
  471. *
  472. *   SYNOPSIS
  473. *        CloseLibObject( library, iorequest, flags )
  474. *
  475. *        void CloseLibObject( struct Library *, struct IORequest *, WORD);
  476. *
  477. *   FUNCTION
  478. *        Close a library type object (library, device or resource).
  479. *        Action depends on the given flags.
  480. *
  481. *   INPUTS
  482. *        library = pointer to a library, device or resource or NULL for no
  483. *                  action
  484. *        iorequest = pointer to an iorequest used to open a device
  485. *                    (only for devices)
  486. *        flags = flags indicating the type of library to close.
  487. *
  488. *   RESULT
  489. *
  490. *   NOTES
  491. *
  492. *   BUGS
  493. *
  494. *   SEE ALSO
  495. *        OpenLibObject(), patch.h
  496. *
  497. ******************************************************************************
  498. *
  499. */
  500. void CloseLibObject( struct Library *libbase, struct IORequest *iorequest, WORD flags)
  501. {
  502.     if( libbase)
  503.     {
  504.         if( flags & MPSF_CloseDev)
  505.         {
  506.             if( iorequest)
  507.             {
  508.                 CloseDevice( iorequest);
  509.                 AFreemem( iorequest);
  510.             }
  511.         }
  512.  
  513.         if( flags & MPSF_CloseLib)
  514.         {
  515.             CloseLibrary( libbase);
  516.         }
  517.  
  518.         if( flags & MPSF_IncLibUsage)
  519.         {
  520.             libbase->lib_OpenCnt--;    /* ATOMIC operation */
  521.         }
  522.     }
  523. }
  524.  
  525.  
  526. /****i* patch.library/CallRemoveHooks ***************************************
  527. *
  528. *   NAME
  529. *        CallRemoveHooks -- Call all hooks, when removing a patch.
  530. *
  531. *   SYNOPSIS
  532. *        CallRemoveHooks( patch )
  533. *
  534. *        void CallRemoveHooks( struct Patch *);
  535. *
  536. *   FUNCTION
  537. *        Call all hooks, because the given patch structure, will be removed.
  538. *
  539. *   INPUTS
  540. *        patch = pointer to a Patch structure
  541. *
  542. *   RESULT
  543. *
  544. *   NOTES
  545. *
  546. *   BUGS
  547. *
  548. *   SEE ALSO
  549. *        AddRemoveHook(), patch.h
  550. *
  551. ******************************************************************************
  552. *
  553. */
  554. void CallRemoveHooks( struct Patch *patch)
  555. {
  556. struct Node *pointer; 
  557.  
  558.     for (pointer = (struct Node *)patch->PS_RemoveHookList.lh_Head;
  559.          pointer->ln_Succ;
  560.          pointer = (struct Node *)pointer->ln_Succ)
  561.     {
  562.         CallHookA( (struct Hook *)pointer, (APTR)patch, 0L);
  563.     }
  564. }
  565.  
  566.  
  567. /****i* patch.library/LinkPatch ***************************************
  568. *
  569. *   NAME
  570. *        LinkPatch -- Establish new links between patch structures.
  571. *
  572. *   SYNOPSIS
  573. *        LinkPatch( master )
  574. *
  575. *        void LinkPatch( struct MasterPatch *);
  576. *
  577. *   FUNCTION
  578. *        This is one of the core functions of patch.library.
  579. *        It corrects the sequence of patches within a patched function,
  580. *        by changing the jmp instructions and syncronices patch structures
  581. *        with patch codes.
  582. *
  583. *   INPUTS
  584. *        master = pointer to a MasterPatch structure
  585. *
  586. *   RESULT
  587. *
  588. *   NOTES
  589. *        This routine should never fail.
  590. *        This routine should run disabled until a caches can be flushed out.
  591. *
  592. *   BUGS
  593. *        Should use a sub-function, when a doing the code changes (portability),
  594. *        which could as well only flush the needed cachelines, if they
  595. *        actually changed.
  596. *
  597. *   SEE ALSO
  598. *        patch.h
  599. *
  600. ******************************************************************************
  601. *
  602. */
  603.  
  604. void LinkPatch( struct MasterPatch *master)
  605. {
  606. struct Patch *orig;
  607. struct Patch *patch;
  608. struct Patch *endt;
  609. APTR origpatch;
  610. APTR endpatch;
  611. APTR nextpatch1;
  612. APTR nextpatch2;
  613. BOOL replacedflag = FALSE;
  614.  
  615.     orig = (struct Patch *)FindType( (struct List *)(&(master->MPS_PatchHeader)), PS_TYPE_ORIG);
  616.     origpatch = &(orig->PS_PatchCode->PC_PatchCodeStart);
  617.  
  618.     endt = (struct Patch *)master->MPS_PatchHeader.mlh_TailPred;
  619.     endpatch = &(endt->PS_PatchCode->PC_PatchCodeStart);
  620.     nextpatch1 = endpatch;
  621.     nextpatch2 = endpatch;
  622.  
  623.  
  624.     for( patch = endt;
  625.          patch->PS_Node.ln_Pred;
  626.          patch = (struct Patch *)patch->PS_Node.ln_Pred)
  627.  
  628.     {
  629.         switch( patch->PS_Node.ln_Type)
  630.         {
  631.             case PS_TYPE_ORIG:
  632.                 SetJMPInstr( patch->PS_JmpNext, nextpatch1);
  633.  
  634.                 if( replacedflag == FALSE)
  635.                     nextpatch2 = &(patch->PS_PatchCode->PC_PatchCodeStart);
  636.                 break;
  637.  
  638.             case PS_TYPE_SYSTEM:
  639.             case PS_TYPE_USER:
  640.                 if( patch->PS_Node.ln_Pri)
  641.                 {
  642.                     if( patch->PS_Flags & PSF_OriginalType)
  643.                     {
  644.                         SetJMPInstr( patch->PS_JmpOrig, endpatch);
  645.                     }
  646.                     else
  647.                     {
  648.                         SetJMPInstr( patch->PS_JmpOrig, nextpatch2);
  649.                     }
  650.                     SetJMPInstr( patch->PS_JmpNext, nextpatch2);
  651.                     nextpatch1 = &(patch->PS_PatchCode->PC_PatchCodeStart);
  652.                     nextpatch2 = nextpatch1;
  653.                 }
  654.                 else
  655.                 {
  656.                     SetJMPInstr( patch->PS_JmpOrig, origpatch);
  657.                     SetJMPInstr( patch->PS_JmpNext, nextpatch1);
  658.                     nextpatch2 = &(patch->PS_PatchCode->PC_PatchCodeStart);
  659.                     replacedflag = TRUE;
  660.                 }
  661.                 break;
  662.  
  663.             case PS_TYPE_START:
  664.                 SetJMPInstr( patch->PS_JmpNext, nextpatch2);
  665.                 break;
  666.  
  667.             case PS_TYPE_END:
  668.                 nextpatch1 = &(patch->PS_PatchCode->PC_PatchCodeStart);
  669.                 nextpatch2 = nextpatch1;
  670.                 break;
  671.         }
  672.     }
  673. }
  674.